package com.huahua.api.util;

import org.springframework.http.server.reactive.ServerHttpRequest;
import reactor.core.publisher.Mono;

import java.util.Optional;

/**
 * 自定义访问对象工具类
 * <p>
 * 获取对象的IP地址等信息
 *
 * @author X-rapido
 */
public class CusAccessObjectUtil {

    /**
     * 获取用户真实IP地址 - 反应式版本
     * 不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
     * 参考文章： http://developer.51cto.com/art/201111/305181.htm
     * <p>
     * 可是，如果通过了多级反向代理的话，X-Forwarded-For的值并不止一个，而是一串IP值，究竟哪个才是真正的用户端的真实IP呢？
     * 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
     * <p>
     * 如：X-Forwarded-For：192.168.1.110, 192.168.1.120, 192.168.1.130,
     * 192.168.1.100
     * <p>
     * 用户真实IP为： 192.168.1.110
     *
     * @param request ServerHttpRequest对象
     * @return Mono<String> 包含IP地址的反应式流
     */
    public static Mono<String> getIpAddressReactive(ServerHttpRequest request) {
        return Mono.fromCallable(() -> {
            // 按优先级检查各个header
            String[] headers = {
                    "x-real-ip",
                    "x-forwarded-for",
                    "Proxy-Client-IP",
                    "WL-Proxy-Client-IP",
                    "HTTP_CLIENT_IP",
                    "HTTP_X_FORWARDED_FOR"
            };

            for (String header : headers) {
                String ip = request.getHeaders().getFirst(header);
                if (isValidIp(ip)) {
                    // 如果是x-forwarded-for，取第一个IP
                    if ("x-forwarded-for".equalsIgnoreCase(header) && ip.contains(",")) {
                        ip = ip.split(",")[0].trim();
                    }
                    return ip;
                }
            }

            // 如果所有header都没有有效IP，则使用远程地址
            return Optional.ofNullable(request.getRemoteAddress())
                    .map(address -> address.getAddress().getHostAddress())
                    .orElse("unknown");
        });
    }

    /**
     * 检查IP地址是否有效
     *
     * @param ip IP地址字符串
     * @return 是否有效
     */
    private static boolean isValidIp(String ip) {
        return ip != null && ip.length() > 0 && !"unknown".equalsIgnoreCase(ip);
    }

    /**
     * 获取用户真实IP地址 - 同步版本
     * 适用于需要立即获取IP地址的场景
     *
     * @param request ServerHttpRequest对象
     * @return IP地址字符串
     */
    public static String getIpAddress(ServerHttpRequest request) {
        // 按优先级检查各个header
        String[] headers = {
                "x-real-ip",
                "x-forwarded-for",
                "Proxy-Client-IP",
                "WL-Proxy-Client-IP",
                "HTTP_CLIENT_IP",
                "HTTP_X_FORWARDED_FOR"
        };

        for (String header : headers) {
            String ip = request.getHeaders().getFirst(header);
            if (isValidIp(ip)) {
                // 如果是x-forwarded-for，取第一个IP
                if ("x-forwarded-for".equalsIgnoreCase(header) && ip.contains(",")) {
                    ip = ip.split(",")[0].trim();
                }
                return ip;
            }
        }

        // 如果所有header都没有有效IP，则使用远程地址
        return Optional.ofNullable(request.getRemoteAddress())
                .map(address -> address.getAddress().getHostAddress())
                .orElse("unknown");
    }

}
